package org.zoomdev.zoom.ioc.impl;

import org.zoomdev.zoom.common.utils.Classes;
import org.zoomdev.zoom.ioc.IocException;
import org.zoomdev.zoom.ioc.IocKey;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

public final class IocCreateContext {

    private final Set<IocKey> constructing = new HashSet<>();
    Map<IocKey, List<FieldInjectInfo>> fields = new HashMap<IocKey, List<FieldInjectInfo>>();

    public void addConstructing(IocKey obj) {
        constructing.add(obj);
    }

    public boolean isConstructing(IocKey obj) {
        return constructing.contains(obj);
    }

    public void removeConstructing(IocKey key, Object obj) {
        constructing.remove(key);

        List<FieldInjectInfo> pairs = fields.get(key);
        if (pairs != null) {
            for (FieldInjectInfo pair : pairs) {
                try {
                    pair.inject(obj);
                } catch (Throwable e) {
                    throw new IocException("完成注入失败", Classes.getCause(e));
                }
            }
        }
    }

    public void addField(IocKey key, Field field, Object obj) {
        List<FieldInjectInfo> pairs = fields.get(key);
        if (pairs == null) {
            pairs = new ArrayList<FieldInjectInfo>();
            fields.put(key, pairs);
        }
        pairs.add(new FieldInjectInfo(field, obj));
    }

    public static class FieldInjectInfo {
        public Field field;
        public Object obj;

        public FieldInjectInfo(Field field, Object obj) {
            this.field = field;
            this.obj = obj;
        }

        public void inject(Object obj) throws Throwable {
            this.field.set(this.obj, obj);
        }
    }

}
